pub mod buffer;
pub mod command_pool;
pub mod queue;
pub mod swapchain;
pub mod command_buffer;
pub mod pipeline;
pub mod sync;

use ash::{self, Entry, vk};

use crate::VK_CHECK;
use crate::VK_CHECK_UNSAFE;
use crate::VK_LOGP;
use crate::VK_LOGV;
use crate::system::window::WindowSystem;

use super::VkConfig;
use super::VkContext;
use super::vk_struct::QueueType;
use super::vk_struct::VkDebugUtils;
use super::vk_struct::VkFamilyQueue;
use super::vk_struct::VkQueue;
use super::vk_struct::VkSurface;
use super::vk_struct::VkSwapchain;

impl VkContext {
    pub fn new(vk_config: &mut VkConfig, g_window_system: &WindowSystem) -> Self {
        // Core Part
        let vk_entry                = Self::init_entry();
        let vk_instance             = Self::init_instance(vk_config, &vk_entry);

        // Window Part
        let g_window                = g_window_system.w_window.clone();
        let vk_surface              = VkSurface::new(&vk_entry, &vk_instance, &g_window_system.w_window);
        
        let vk_debug_utils          = Self::init_debug_utils(vk_config, &vk_entry, &vk_instance);
        let vk_physical_device      = Self::init_physical_device(vk_config, &vk_instance, &vk_surface);
        let vk_device               = Self::init_device(vk_config, &vk_instance, &vk_physical_device);
        let vk_queue_map            = Self::init_queue_map(vk_config, &vk_device);
        let vk_command_pool         = Self::init_command_pool(&vk_device, &vk_queue_map);

        let vk_descriptor_pool      = Self::init_descriptor_pool(&vk_device);

        Self {            
            vk_entry                : vk_entry,
            vk_instance             : vk_instance,
            g_window                : g_window,
            vk_surface              : vk_surface,
    
            vk_debug_utils          : vk_debug_utils,
            vk_physical_device      : vk_physical_device,
            vk_device               : vk_device,
            vk_queue_map            : vk_queue_map,
            vk_command_pool         : vk_command_pool,
            vk_descriptor_pool      : vk_descriptor_pool,

            current_frame_index     : 0,
            current_image_index     : 0,
            current_command_buffer  : vk::CommandBuffer::null(),

            verbose_log             : vk_config.verbose_log
        }
    }

    /// 初始化Entry
    /// 这个是Ash特有的一个结构
    fn init_entry() -> Entry {
        match unsafe { Entry::load() } {
            Ok(entry) => {entry},
            Err(_) => { VK_LOGP!("Failed to Load Entry") }
        }
    }

    /// 初始化Instance
    /// 注意这个Instance并不是Handler，而是FunctionSet，里面包住了原始的Handler
    fn init_instance(vk_config: &VkConfig, vk_entry: &Entry) -> ash::Instance {
        // Check Version
        if vk_config.verbose_log {
            vk_config.check_enumerate_instance_version(vk_entry);
        }

        // Check Layers
        if let Some(instance_layer_properties) = VK_CHECK!(vk_entry.enumerate_instance_layer_properties()) {
            vk_config.check_required_layer(instance_layer_properties);
        }

        // Check Extensions
        if let Some(instance_extension_properties) = VK_CHECK!(vk_entry.enumerate_instance_extension_properties(None)) {
            vk_config.check_required_extension(instance_extension_properties);
        }

        // Create Info
        // 这里不写在一行看get_required_layer_names的注释
        let required_layer_names                = vk_config.get_required_layer_names();
        let required_extension_names            = vk_config.get_required_extension_names();

        let mut instance_ci = vk_config.get_instance_ci();
        instance_ci.p_application_info          = &vk_config.get_application_info();
        instance_ci.enabled_layer_count         = vk_config.required_layer_names.len() as u32;
        instance_ci.pp_enabled_layer_names      = required_layer_names.as_ptr();
        instance_ci.enabled_extension_count     = vk_config.required_extension_names.len() as u32;
        instance_ci.pp_enabled_extension_names  = required_extension_names.as_ptr();

        match VK_CHECK_UNSAFE!(vk_entry.create_instance(&instance_ci, None)) {
            Some(vk_instance) => vk_instance,
            None => panic!()
        }
    }

    fn init_debug_utils(vk_config: &VkConfig, vk_entry: &ash::Entry, vk_instance: &ash::Instance) -> Option<VkDebugUtils> {
        if !vk_config.use_debug_utils {
            return None
        }
        Some(VkDebugUtils::new(vk_config, vk_entry, vk_instance))
    }

    fn init_physical_device(vk_config: &mut VkConfig, vk_instance: &ash::Instance, vk_surface: &VkSurface) -> ash::vk::PhysicalDevice {
        // Get All Physical Devices
        let physical_devices = match VK_CHECK_UNSAFE!(vk_instance.enumerate_physical_devices()) {
            Some(physical_devices) => {physical_devices},
            None => { VK_LOGP!("Failed to Load Physical devices") }
        };

        // 遍历设备
        for vk_physical_device in &physical_devices {
            if vk_config.check_physical_device(vk_instance, vk_surface, vk_physical_device) {
                return *vk_physical_device
            }
        }

        VK_LOGP!("Failed to find suitable physical device");
    }

    fn init_device(vk_config: &VkConfig, vk_instance: &ash::Instance, vk_physical_device: &vk::PhysicalDevice) -> ash::Device {
        let family_queues = vk_config.get_merged_family_queues();
        // 然后根据family_queue目前存的信息生成create info
        let mut queue_ci_list = vec![];
        for family_queue in &family_queues {
            if family_queue.queue_count > 0 {
                queue_ci_list.push(family_queue.get_queue_ci())
            }
        }
        // Create Info
        // 这里不写在一行看get_required_layer_names的注释
        let required_device_extension_names     = vk_config.get_required_device_extension_names();

        let mut device_ci = vk_config.get_device_ci();
        device_ci.queue_create_info_count       = queue_ci_list.len() as u32;
        device_ci.p_queue_create_infos          = queue_ci_list.as_ptr();
        // device_ci.enabled_layer_count = ;
        // device_ci.pp_enabled_layer_names = ;
        device_ci.enabled_extension_count       = vk_config.required_device_extension_names.len() as u32;
        device_ci.pp_enabled_extension_names    = required_device_extension_names.as_ptr();

        match VK_CHECK_UNSAFE!(vk_instance.create_device(*vk_physical_device, &device_ci, None)) {
            Some(inner_value)       => inner_value,
            None                    => VK_LOGP!("Failed to create_device")
        }
    }

    /// 生成
    /// QueueType的数字编号 => VkQueue序列
    /// 的映射
    fn init_queue_map(vk_config :&VkConfig, vk_device: &ash::Device) -> Vec<Vec<VkQueue>> {
        let mut vk_queue_map = vec![];

        for _ in 0..QueueType::COUNTER as u32 {
            vk_queue_map.push(vec![]);
        }

        for supported_queue in &vk_config.supported_queues {
            let queue_handler = unsafe {
                vk_device.get_device_queue(supported_queue.family_index, supported_queue.queue_index)
            };
            vk_queue_map[supported_queue.queue_type as usize].push(VkQueue {
                handler         : queue_handler,
                queue_index     : supported_queue.queue_index,
                family_index    : supported_queue.family_index 
            });
        }

        vk_queue_map
    }

    fn init_descriptor_pool(vk_device: &ash::Device) -> vk::DescriptorPool {
        let descriptor_pool_size = [
            vk::DescriptorPoolSize {
                ty: vk::DescriptorType::UNIFORM_BUFFER,
                descriptor_count: 8000
            },
            vk::DescriptorPoolSize {
                ty: vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
                descriptor_count: 8
            },  
            vk::DescriptorPoolSize {
                ty: vk::DescriptorType::STORAGE_BUFFER,
                descriptor_count: 8
            },
            vk::DescriptorPoolSize {
                ty: vk::DescriptorType::INPUT_ATTACHMENT,
                descriptor_count: 8
            },
        ];

        let descriptor_pool_create_info = vk::DescriptorPoolCreateInfo {
            s_type                      : vk::StructureType::DESCRIPTOR_POOL_CREATE_INFO,
            p_next                      : std::ptr::null(),
            flags                       : vk::DescriptorPoolCreateFlags::FREE_DESCRIPTOR_SET,
            max_sets                    : 8000,
            pool_size_count             : descriptor_pool_size.len() as u32,
            p_pool_sizes                : descriptor_pool_size.as_ptr()
        };

        match VK_CHECK_UNSAFE!(vk_device.create_descriptor_pool(&descriptor_pool_create_info, None)) {
            Some(inner_value)       => inner_value,
            None                    => VK_LOGP!("Failed to create_descriptor_pool")
        }
    }
}